package com.kaifamiao.high.reflect;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * @author lucien-ma
 * @date 2021/9/27
 * @apiNote
 */
public class Demo01 {
    public static void main(String[] args) {
        Set<Method> classAllMethod = getClassAllMethod(Student.class);
        for (Method method : classAllMethod) {
            System.out.println(method);
        }
    }

    /**
     * 返回这个类中的所有方法（包括从父类继承的以及本类中声明的所有方法）
     * private 方法算未继承
     * 只考虑直接父类
     * @param clazz 这个类的 Class 对象
     * @return 返回所有方法的 set 集合
     *
     * 分析：
     *    如果说这个类的直接父类不是 Object
     *    那么就有可能存在这个类的直接父类和它同包的情况
     *    在同包的情况下，默认访问修饰符的方法是可以被继承并且调用的
     *    但是 getMethods 方法只能获取父类中被 public 修饰的方法
     *    所以我们有必要在直接父类不是 Object 并且是同包的情况下，
     *    获取父类的 Class 对象从而拿到默认修饰符的方法
     *
     */
    public static Set<Method> getClassAllMethod(Class clazz) {
        Set<Method> allMethod = new HashSet<>();
        if (!(clazz.getSuperclass().equals(Object.class)) &&
                clazz.getPackage().equals(clazz.getSuperclass().getPackage())) {
            // 此方法进来说明 直接父类不是 Object，且同包
            // 父类的方法
            Class superclass = clazz.getSuperclass();
            Method[] superMethods = superclass.getDeclaredMethods();
            for (Method superMethod : superMethods) {
                if (!superMethod.toString().startsWith("private")){
                    // 不是 private 就放进来
                    allMethod.add(superMethod);
                }
            }
            // 本身的方法
            Method[] selfMethods = clazz.getDeclaredMethods();
            for (Method selfMethod : selfMethods) {
                allMethod.add(selfMethod);
            }
        } else {
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                allMethod.add(method);
            }
            Method[] declaredMethods = clazz.getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                allMethod.add(declaredMethod);
            }
        }
        return allMethod;
    }
}
